// DriveRoot.cpp : Implementation of CDriveRoot

#include "stdafx.h"
#include "DriveRoot.h"
#include "AIDDriveUtils.h"
#include "AIDEnumIDList.h"

// CDriveRoot

HRESULT WINAPI CDriveRoot::UpdateRegistry(BOOL bRegister) throw()
{
	HRESULT hr = S_OK;
	REFKNOWNFOLDERID computerRfid = FOLDERID_ComputerFolder;

	CComBSTR bstrCLSID = CLSID_DriveRoot;

	CComBSTR bstrProjectName, bstrDisplayName, bstrDescription, bstrUrlProtocol, bstrAttribs, bstrPreviewHost;
	CComBSTR bstrLocation = L"MyComputer";
	bstrProjectName.LoadString(IDS_PROJNAME);
	bstrDisplayName.LoadString(IDS_DISPLAY_NAME);
	bstrDescription.LoadString(IDS_DESCRIPTION);
	bstrPreviewHost = L"{6D2B5079-2F0B-48DD-AB7F-97CEC514D30B}";
	
	// 32bit PreviewHost under 64bit Windows
	BOOL bIsWOW64 = FALSE; 
	::IsWow64Process(::GetCurrentProcess(), &bIsWOW64);
	
	if( bIsWOW64 ) 
		bstrPreviewHost = L"{534A1E02-D58F-44F0-B58B-36CBED287C7C}";
	//bstrAttribs = L"&HB8C00153";
	DWORD dwAttr = 0;
	dwAttr |= SFGAO_CANCOPY 
              | SFGAO_CANMOVE 
              | SFGAO_CANRENAME 
              | SFGAO_DROPTARGET
              //| SFGAO_STREAM
              | SFGAO_FOLDER 
              | SFGAO_BROWSABLE 
              | SFGAO_HASSUBFOLDER 
              | SFGAO_HASPROPSHEET 
              | SFGAO_FILESYSANCESTOR
              | SFGAO_STORAGEANCESTOR;
	WCHAR wszTemp[50];
	::wsprintf(wszTemp, L"&H%08X", dwAttr); 
	bstrAttribs = wszTemp;

	_ATL_REGMAP_ENTRY regMapEntries[] =
	{
      { L"CLSID", bstrCLSID },
      { L"PROJECTNAME", bstrProjectName },
      { L"DISPLAYNAME", bstrDisplayName },
      { L"DESCRIPTION", bstrDescription },
      { L"LOCATION", bstrLocation },
      { L"PREVIEWHOST", bstrPreviewHost },
	  { L"FOLDERATTRIBS", bstrAttribs},
	  { NULL, NULL }
   };
	
	hr = _AtlModule.UpdateRegistryFromResource(IDR_DRIVEROOT, bRegister, regMapEntries);
	if( SUCCEEDED(hr) ) {
		hr = _AtlModule.UpdateRegistryFromResource(IDR_EXPLORER_REG, bRegister, regMapEntries);
	}

	//CPidl pidlKnownFolder;

	PIDLIST_ABSOLUTE pidlKnownFolder = AIDDriveUtils::CreateFromKnownFolder(computerRfid);
	
	::SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST, pidlKnownFolder, NULL);
	::SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
	
	return hr;
}

HRESULT	CDriveRoot::FinalConstruct()
{
	ATLTRACE(L"CDriveRoot::FinalConstruct\n");
	
	return S_OK;
}

void CDriveRoot::FinalRelease()
{
	ATLTRACE(L"CDriveRoot::FinalRelease\n");
}

STDMETHODIMP CDriveRoot::ParseDisplayName(HWND hwnd, IBindCtx* pbc, PWSTR pszDisplayName, ULONG* pchEaten, PIDLIST_RELATIVE* ppidl, ULONG* pdwAttributes)
{
	ATLTRACE(L"CDriveRoot::ParseDisplayName  name='%ws' pbc=%p\n", pszDisplayName, pbc);
	return E_NOTIMPL;
}

STDMETHODIMP CDriveRoot::EnumObjects(HWND hwnd, SHCONTF grfFlags, IEnumIDList** ppEnumIDList)
{
	ATLTRACE(L"CDriveRoot::EnumObjects  hwnd=%X grf=0x%X\n", hwnd, grfFlags);
	//return E_NOTIMPL;
	CComObject<AIDEnumIDList> *pEnum;
	HRESULT Hr = CComObject<AIDEnumIDList>::CreateInstance(&pEnum);
	if (SUCCEEDED(Hr))
	{
		// AddRef() the object while we're using it.
		pEnum->AddRef();

		// Init the enumerator.  Init() will AddRef() our IUnknown (obtained with
		// GetUnknown()) so this object will stay alive as long as the enumerator 
		// needs access to the collection m_NEFileArray.
		//Hr = pEnum->_Init(m_pidlPath, dwFlags);

		// Return an IEnumIDList interface to the caller.
		//if (SUCCEEDED(Hr))
			Hr = pEnum->QueryInterface(IID_IEnumIDList, (void**)ppEnumIDList);

		pEnum->Release();
	}
	
	return Hr;
}

STDMETHODIMP CDriveRoot::BindToObject(PCUIDLIST_RELATIVE pidl, IBindCtx* pbc, REFIID riid, LPVOID* ppRetVal)
{
	//return E_NOTIMPL;
	ATLTRACE(L"CDriveRoot::BindToObject  riid=%s pidl = %s\n", AIDDriveUtils::DbgGetIID(riid), AIDDriveUtils::DbgGetPidl(pidl));
   	
	ATLASSERT(ILIsChild(pidl));
   	PCUITEMID_CHILD pidlItem = static_cast<PCUITEMID_CHILD>(pidl);
   	// Attach to child folder?
   	if( riid == IID_IShellFolder || riid == IID_IShellFolder2)
   	{
		CComObject<CDriveRoot> *pVFObj=0;
		HRESULT hr;
		hr=CComObject<CDriveRoot>::CreateInstance(&pVFObj);
		if(FAILED(hr))
			return hr;

		pVFObj->AddRef();

		//LPITEMIDLIST pidlNew = m_PidlMgr.Concatenate(m_pidlPath,pidl);
		//pVFObj->m_pidlPath = m_PidlMgr.Copy(pidlNew);	
		//m_PidlMgr.Delete(pidlNew);

		hr=pVFObj->QueryInterface(riid, ppRetVal);

		ATLASSERT(pVFObj);
		pVFObj->Release();

		return hr;
	   
   	}

   	// Process standard objects...
 //  	if( riid == IID_IStream )
 //  	{
 //  	   
 //  	}
 //  	if( riid == IID_IMoniker )
 //  	{
	//		
 //  	}
 //  	if( riid == IID_IPropertyStoreFactory )
 //  	{      
	//		
 //  	}
 //  	if( riid == IID_IPropertyStore )
 //  	{     
	//	   
 //  	}	 
 //  	if( riid == IID_IPropertySetStorage )
 //  	{
 //  	   
 //  	}
 //  	if( riid == IID_IExtractImage )
 //  	{
 //  	   
 //  	}
	//if( riid == IID_IThumbnailProvider)
	//{
	//	
	//}
	//if( riid == IID_ITransferMediumItem )
	//{
	//	
	//}
	//if( riid == IID_IIdentityName )
	//{
	//		
	//}
   	ATLTRACE(L"CDriveRoot::BindToObject - failed\n");
   	return E_NOINTERFACE;
}

STDMETHODIMP CDriveRoot::BindToStorage(PCUIDLIST_RELATIVE pidl, IBindCtx* pbc, REFIID riid, LPVOID* ppRetVal)
{
	ATLTRACE(L"CDriveRoot::BindToStorage\n", this);
	
	return E_NOTIMPL;
}

STDMETHODIMP CDriveRoot::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
{
	ATLTRACE(L"CDriveRoot::CompareIDs  column=%u flags=0x%X\n", LOWORD(lParam), HIWORD(lParam));
	return E_NOTIMPL;	
}

STDMETHODIMP CDriveRoot::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID* ppRetVal)
{
	ATLTRACE(L"CDriveRoot::CreateViewObject  riid=%s\n", AIDDriveUtils::DbgGetIID(riid));
	if( riid == IID_IShellView )
	{
		
		//m_hwndOwner = hwndOwner;
		SFV_CREATE sfvData = { sizeof(sfvData), 0 };
		CComQIPtr<IShellFolder> spFolder = GetUnknown();
		sfvData.psfvcb = this;
		sfvData.pshf = spFolder;
		HRESULT hr = ::SHCreateShellFolderView(&sfvData, (IShellView**) ppRetVal);
		_ASSERTE (hr == S_OK);
		return hr;
	}
	if( riid == IID_IDropTarget) 
	{
		
	}
	if( riid == IID_IContextMenu)
	{
		
	}
	if( riid == IID_IExplorerCommandProvider)
	{
		
	}
	if( riid == IID_ICategoryProvider)
	{
		
	}
	if( riid == IID_ITransferSource)
	{
		
	}
	if( riid == IID_ITransferDestination)
	{
		
	}
	if( riid == CLSID_DriveRoot)
	{
		
	}
   
	HRESULT res = QueryInterface(riid, ppRetVal);
	
	return res;
}

STDMETHODIMP CDriveRoot::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY rgpidl, REFIID riid, UINT* rgfReserved, LPVOID* ppRetVal)
{
	ATLTRACE(L"CDriveRoot::GetUIObjectOf  count=%u riid=%s\n", cidl, AIDDriveUtils::DbgGetIID(riid));
	

	return E_NOTIMPL;
}

STDMETHODIMP CDriveRoot::GetDisplayNameOf(PCUITEMID_CHILD pidl, SHGDNF uFlags, STRRET* psrName)
{
	ATLTRACE(L"CDriveRoot::GetDisplayNameOf  flags=0x%04X\n", uFlags);

	return E_NOTIMPL;
}

STDMETHODIMP CDriveRoot::SetNameOf(HWND hwnd, PCUITEMID_CHILD pidl, LPCWSTR pszName, SHGDNF uFlags, PITEMID_CHILD* ppidlOut)
{
	ATLTRACE(L"CDriveRoot::SetNameOf\n");
	return E_NOTIMPL;
}

STDMETHODIMP  CDriveRoot::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY rgpidl, SFGAOF* rgfInOut)
{
	ATLTRACE(L"CDriveRoot::GetAttributesOf  count=%u rgf=0x%08X\n", cidl, *rgfInOut);

	return E_NOTIMPL;
}

STDMETHODIMP CDriveRoot::GetDefaultSearchGUID(GUID* pguid)
{
	ATLTRACENOTIMPL(L"CDriveRoot::GetDefaultSearchGUID\n");
}

STDMETHODIMP CDriveRoot::EnumSearches(IEnumExtraSearch** ppenum)
{
	ATLTRACENOTIMPL(L"CDriveRoot::EnumSearches\n");
}

STDMETHODIMP CDriveRoot::GetDefaultColumn(DWORD /*dwRes*/, ULONG* pSort, ULONG* pDisplay)
{
	ATLTRACENOTIMPL(L"CDriveRoot::GetDefaultColumn\n");
}

STDMETHODIMP CDriveRoot::GetDefaultColumnState(UINT iColumn, SHCOLSTATEF* pcsFlags)
{
   	
	ATLTRACENOTIMPL(L"CDriveRoot::GetDefaultColumnState\n");
}

STDMETHODIMP CDriveRoot::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID* pscid, VARIANT* pv)
{
   	ATLTRACE(L"CDriveRoot::GetDetailsEx  scid=%s\n"/*, DbgGetPKEY(*pscid)*/);
	ATLTRACENOTIMPL(L"CDriveRoot::GetDetailsEx\n");
}

STDMETHODIMP CDriveRoot::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS* psd)
{
	ATLTRACE(L"CDriveRoot::GetDetailsOf  column=%u\n", iColumn);
	SHCOLUMNID scid = { 0 };
	if (iColumn < 5)
		return S_OK;
	else
		return E_FAIL;
	//return S_OK;
	//ATLTRACENOTIMPL(L"CDriveRoot::GetDetailsOf\n");
}

STDMETHODIMP CDriveRoot::MapColumnToSCID(UINT iColumn, SHCOLUMNID* pscid)
{ 
	ATLTRACE(L"CDriveRoot::MapColumnToSCID  column=%u\n", iColumn);
	
	switch (iColumn)	
	{
	case 0:
		*pscid = PKEY_ItemNameDisplay;
	break;
	case 1:
		*pscid = PKEY_ItemNameDisplay;
	break;            
	case 2:
		*pscid = PKEY_ItemPathDisplay;
	break;            
	case 3:
		*pscid = PKEY_Contact_FullName;
	break;           
	case 4:
		*pscid = PKEY_Contact_PrimaryAddressCity;
	break; 
	case 5:
		*pscid = PKEY_FileName;
	break;                   
	case 6:
		*pscid = PKEY_FileAttributes;
	break;             
	case 7:
		*pscid = PKEY_ParsingPath;
	break;                
	case 8:
		*pscid = PKEY_ItemPathDisplayNarrow;
	break;      
	case 9:
		*pscid = PKEY_SFGAOFlags;
	break;                 
	case 10:
		*pscid = PKEY_Volume_IsRoot;
	break;              
	case 11:
		*pscid = PKEY_PropList_InfoTip;
	break;           
	case 12:
		*pscid = PKEY_PropList_TileInfo;
	break;          
	case 13:
		*pscid = PKEY_PropList_FullDetails;
	break;       
	case 14:
		*pscid = PKEY_PropList_PreviewTitle;
	break;      
	case 15:
		*pscid = PKEY_PropList_PreviewDetails;
	break;    
	case 16:
		*pscid = PKEY_PropList_ExtendedTileInfo;
	break;  
	default:
		return E_FAIL;
	}
   return S_OK;
}       

// IPersist

STDMETHODIMP CDriveRoot::GetClassID(CLSID* pclsid)
{
	ATLTRACE(L"CDriveRoot::GetClassID\n");
	*pclsid = GetObjectCLSID();
	return S_OK;
}

// IPersistFolder

STDMETHODIMP CDriveRoot::Initialize(PCIDLIST_ABSOLUTE pidl)
{
   	//
	//ATLTRACENOTIMPL(L"CDriveRoot::Initialize\n");
	ATLTRACE(L"CDriveRoot::Initialize: %s\n", AIDDriveUtils::DbgGetPidl(pidl));
	m_root.Delete();
	m_crtFolder.Delete();

	m_root		= pidl;
	m_crtFolder = pidl;
	
	return S_OK;
}

// IPersistFolder2
STDMETHODIMP CDriveRoot::GetCurFolder(PIDLIST_ABSOLUTE* ppidl)
{
   	
	ATLTRACE(L"CDriveRoot::GetCurFolder\n");
	return m_crtFolder.CopyTo(ppidl);
}

// IPersistFolder3
STDMETHODIMP CDriveRoot::InitializeEx(IBindCtx* pbc, PCIDLIST_ABSOLUTE pidlRoot, const PERSIST_FOLDER_TARGET_INFO* pPFTI)
{
	ATLTRACENOTIMPL(L"CDriveRoot::InitializeEx\n");
}
STDMETHODIMP CDriveRoot::GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO* pPFTI)
{
   ::ZeroMemory(pPFTI, sizeof(PERSIST_FOLDER_TARGET_INFO));
   
   ATLTRACENOTIMPL(L"CDriveRoot::GetFolderTargetInfo");
}

// IShellFolderViewCB messages

LRESULT CDriveRoot::OnWindowCreated(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	ATLTRACE(L"CDriveRoot::OnWindowCreated");	
	return 0;
}

LRESULT CDriveRoot::OnGetNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	ATLTRACE(L"CDriveRoot::OnGetNotify");
	// Tell the Shell we want to receive Change Notifications for our folder.
	// Note the nasty non-owned referenced IDLIST to the Shell here!
	//* reinterpret_cast<PIDLIST_ABSOLUTE*>(wParam) = m_pidlMonitor;
	//* reinterpret_cast<LONG*>(lParam) = SHCNE_DISKEVENTS;
	
	return S_OK;
}
